#include "Next.h"
#include <algorithm>
#include <set>
#include <vector>
#include <map>

Next::Next()
{
}
Next::~Next()
{
}

BOOLEAN Next::IsTransitiveNext(PROG_LINE prev,PROG_LINE next)
{
	PROG_LINE_ARRAY prev_result;
	prev_result = Next::GetTransitiveNext(prev);
	if (prev_result.find(next) != prev_result.end())
		return true;
	return false;
}
void Next::InsertNext(PROG_LINE prev,PROG_LINE next)
{
	/*map<PROG_LINE,PROG_LINE> next_relation;
	next_relation.insert(pair<PROG_LINE,PROG_LINE>(prev,next));
	this->next_store.insert(next_relation);
	*/
	if(next_store.find(prev) != next_store.end())
		this->next_store[prev].insert(next);
	else{
		PROG_LINE_ARRAY next_temp;
		next_temp.insert(next);
		this->next_store.insert(pair<PROG_LINE,PROG_LINE_ARRAY>(prev,next_temp));
	}
	if(prev_store.find(next) != prev_store.end())
		this->prev_store[next].insert(prev);
	else{
		PROG_LINE_ARRAY prev_temp;
		prev_temp.insert(prev);
		this->prev_store.insert(pair<PROG_LINE,PROG_LINE_ARRAY>(next,prev_temp));
	}
}
PROG_LINE_ARRAY Next::GetNext(PROG_LINE prev)
{
	PROG_LINE_ARRAY result;
	/*for (auto it=this->next_store.begin();it!=this->next_store.end();it++){
	  if(it->begin()->first == prev)
		  result.insert(it->begin()->second);
	}*/
	result = this->next_store[prev];
	return result;
}
PROG_LINE_ARRAY Next::GetPrevious(PROG_LINE next)
{
	PROG_LINE_ARRAY result;
	/*for (auto it=this->next_store.begin();it!=this->next_store.end();it++){
	  if(it->begin()->second == next)
		  result.insert(it->begin()->first);
  }*/
	result = this->prev_store[next];
	return result;
}
BOOLEAN Next::IsNext(PROG_LINE prev,PROG_LINE next)
{
	/*for (auto it=this->next_store.begin();it!=this->next_store.end();it++){
		if(it->begin()->first == prev && it->begin()->second == next)
			return true;
	}*/
	PROG_LINE_ARRAY temp;
	temp = this->next_store[prev];
	if(temp.find(next) != temp.end())
		return true;
	return false;
}
set<PROG_LINE> Next::VectorToSet(vector<PROG_LINE> input){
	PROG_LINE_ARRAY result;
	for(auto it=input.begin();it!=input.end();it++)
		result.insert(*it);
	auto zero = result.find(0);
	if (zero != result.end())
		result.erase(zero);
	return result;
}
PROG_LINE_ARRAY Next::GetTransitiveNext(PROG_LINE prev)
{
	PROG_LINE_ARRAY result;
	PROG_LINE_ARRAY temp,temp1;
	vector<PROG_LINE> store(this->next_store.size());
	set<PROG_LINE>::iterator check;
	temp.insert(prev);
	do{
		temp = Next::HelperGetTransitive(temp,1);
		// Delete items that i have searched before
		temp1.clear();
		for(auto i=temp.begin();i!=temp.end();i++)
			if(result.find(*i) == result.end())
				temp1.insert(*i);
		temp = temp1;
		set_union(temp.begin(),temp.end(),result.begin(),result.end(),store.begin());
		result = Next::VectorToSet(store);
		// Prevent from searching from itself again
		check = temp.find(prev);
		if (check != temp.end())
			temp.erase(check);
	}while (temp.size() !=0);
	return result;
}
PROG_LINE_ARRAY Next::GetTransitivePrevious(PROG_LINE next)
{
	PROG_LINE_ARRAY result;
	PROG_LINE_ARRAY temp,temp1;
	vector<PROG_LINE> store(this->next_store.size());
	set<PROG_LINE>::iterator check;
	temp.insert(next);
	do{
		temp = Next::HelperGetTransitive(temp,2);
		// Delete items that i have searched before
		temp1.clear();
		for(auto i=temp.begin();i!=temp.end();i++)
			if(result.find(*i) == result.end())
				temp1.insert(*i);
		temp = temp1;
		set_union(temp.begin(),temp.end(),result.begin(),result.end(),store.begin());
		result = Next::VectorToSet(store);
		// Prevent from searching from itself again
		check = temp.find(next);
		if (check != temp.end())
			temp.erase(check);
	}while (temp.size() !=0);
	return result;
}
set<PROG_LINE> Next::HelperGetTransitive(set<PROG_LINE> input,int operation){
	PROG_LINE_ARRAY temp;
	PROG_LINE_ARRAY temp1;
	vector<PROG_LINE> store(this->next_store.size());
	vector<PROG_LINE> newResult(this->next_store.size());

	for(auto it=input.begin();it!=input.end();it++){
		if (operation == 1)
			temp = Next::GetNext(*it);
		else
			temp = Next::GetPrevious(*it);
		set_union(temp1.begin(),temp1.end(),temp.begin(),temp.end(),store.begin());
		temp1 = Next::VectorToSet(store);
	}
	return temp1;
}
